﻿using System;
using System.Collections.Generic;

using SBPweb.Forge.Contracts.Events;

using SBPweb.Communication.Shared.Library;
using SBPweb.Communication.Shared.Library.Contacts;
using SBPweb.Communication.Shared.Library.Connections;

using SBPweb.Communication.Client.Library.Xmpp.Contacts;

namespace SBPweb.Communication.Client.Library.Xmpp.Connections
{

    partial class ConnectionManager : ConnectionManagerBase
    {

        #region Internal fields

        internal protected Matrix.Xmpp.Client.XmppClient client;

        internal Matrix.Jid localJid;

        #endregion

        #region Constructor logic

        #endregion

        #region Property accessors

        public override string UserName
        {
            get
            {
                return localJid.User;
            }
            protected set
            {
                localJid.User = value;
            }
        }

        public override string Resource
        {
            get
            {
                return client.Resource;
            }
            set
            {
                client.Resource = value;
            }
        }

        #endregion

        #region Methods

        #region Connectivity

        public override void Connect(string userName, string password)
        {
            localJid = new Matrix.Jid(userName, client.Hostname, client.Resource);
            OnConnecting(this, EventArgs.Empty);
            client.Username = userName;
            client.Password = password;
            client.Open();
        }

        public override void Disconnect()
        {
            CancelEventArgs cea = new CancelEventArgs();
            OnDisconnecting(this, cea);
            if (!cea.Cancel)
            {
                client.Close();
            }
        }

        private void OnClientClose(object sender, Matrix.EventArgs e)
        {
            OnDisconnected(sender, EventArgs.Empty);
        }

        private void OnClientError(object sender, Matrix.ExceptionEventArgs e)
        {
            throw e.Exception;
        }

        #endregion

        #region State management

        protected override void OnSetPresenceState(object sender, ContactPresenceStateBaseCancelEventArgs e)
        {
            client.SendPresence(ContactPresenceState.GetShowByAvailabilty(e.State.Availability), e.State.StatusMessage);
        }

        #endregion

        #region Event handlers

        #region Life cycle

        protected override void OnInitialize()
        {
            client = new Matrix.Xmpp.Client.XmppClient();

            //client.XmppDomain = "jabber.org";
            //client.Hostname = "jabber.org";
            //client.Port = 5222;

            //client.XmppDomain = "gmail.com";
            //client.Hostname = "talk.google.com";
            //client.Port = 5222;

            //client.XmppDomain = "jabber.org";
            //client.Hostname = "jabber.org";
            //client.Port = 5222;

            //client.XmppDomain = "ag-software.de";
            //client.Hostname = "matrix.ag-software.de";
            //client.Port = 5222;

            //client.AnonymousLogin = true;

            //client.ProxyType = Matrix.Net.Proxy.ProxyType.HttpTunnel;
            //client.ProxyPort = 4503;
            //client.ProxyHostname = "matrix.ag-software.de";

            client.AutoPresence = Configuration.SendAvailabilityWhenConnected;
            client.ProxyType = Matrix.Net.Proxy.ProxyType.None;
            client.Hostname = Configuration.Server;
            client.XmppDomain = Configuration.Server;
            client.Port = Configuration.Port;
            client.Resource = Configuration.Resource;
            client.Compression = Configuration.IsCompressionNeeded;

            client.Show = ContactPresenceState.GetShowByAvailabilty(Configuration.DefaultAvailability);

            client.OnAuthError += new EventHandler<Matrix.Xmpp.Sasl.SaslEventArgs>(OnClientAuthError);
            client.OnLogin += new EventHandler<Matrix.EventArgs>(OnClientLogin);
            client.OnClose += new EventHandler<Matrix.EventArgs>(OnClientClose);
            client.OnPresence += new EventHandler<Matrix.Xmpp.Client.PresenceEventArgs>(OnPresence);
            client.OnError += new EventHandler<Matrix.ExceptionEventArgs>(OnClientError);
        }

        protected override void OnTerminate()
        {
            if (IsConnected)
            {
                Disconnect();
            }

            client.OnError -= new EventHandler<Matrix.ExceptionEventArgs>(OnClientError);
            client.OnPresence -= new EventHandler<Matrix.Xmpp.Client.PresenceEventArgs>(OnPresence);
            client.OnLogin -= new EventHandler<Matrix.EventArgs>(OnClientLogin);
            client.OnClose -= new EventHandler<Matrix.EventArgs>(OnClientClose);
            client.OnAuthError -= new EventHandler<Matrix.Xmpp.Sasl.SaslEventArgs>(OnClientAuthError);
            client = null;
        }

        #endregion

        #region Client authentication

        private void OnClientAuthError(object sender, Matrix.Xmpp.Sasl.SaslEventArgs e)
        {
            IsConnected = false;
        }

        private void OnClientLogin(object sender, Matrix.EventArgs e)
        {
            IsConnected = true;
            OnConnected(sender, EventArgs.Empty);
        }

        #endregion

        private void OnPresence(object sender, Matrix.Xmpp.Client.PresenceEventArgs e)
        {
            if (e.Presence.From.Equals(localJid))
            {
                OnPresenceStateChanged(sender, new ContactPresenceStateBaseCancelEventArgs(messenger.Contacts.Myself as ContactBase, new ContactPresenceState(e.Presence)));
            }
        }

        #endregion

        #endregion

    }

}